package com.haibara.codesubmiteval.runner;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.haibara.codesubmiteval.constant.AuthConstant;
import com.haibara.codesubmiteval.constant.RedisKeyConstant;
import com.haibara.codesubmiteval.mapper.QuestionMapper;
import com.haibara.codesubmiteval.mapper.QuestionSubmitMapper;
import com.haibara.codesubmiteval.mapper.UserMapper;
import com.haibara.codesubmiteval.model.entity.QuestionSubmit;
import com.haibara.codesubmiteval.model.entity.User;
import com.haibara.codesubmiteval.model.vo.Top10VO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Redis初始化
 */
@Component
@Slf4j
public class RedisDataSyncRunner implements CommandLineRunner {

    @Resource
    private UserMapper userMapper;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private QuestionMapper questionMapper;
    @Resource
    private QuestionSubmitMapper questionSubmitMapper;

    @Override
    public void run(String... args) {
        // 删除旧数据
        String pattern = RedisKeyConstant.getCompleteKey(RedisKeyConstant.userAcceptedQuestionIdsSet, "*");
        Set<String> keys = stringRedisTemplate.keys(pattern);
        if (!keys.isEmpty()) {
            stringRedisTemplate.delete(keys);
        }
        stringRedisTemplate.delete(RedisKeyConstant.top10);
        stringRedisTemplate.delete(RedisKeyConstant.questionNumber);
        // 将数据库中用户完成题目id存入Redis
        List<User> users = userMapper.selectList(null); // 从数据库读取数据
        // ZSet用于构建榜单
        ZSetOperations<String, String> zSetOperations = stringRedisTemplate.opsForZSet();
        SetOperations<String, String> setOperation = stringRedisTemplate.opsForSet();
        for (User user : users) {
            Set<Long> acceptedIdsSet = new HashSet<>(JSONUtil.toList(user.getAcceptedQuestionIds(), Long.class));
            for (Long id : acceptedIdsSet) {
                setOperation.add(
                        RedisKeyConstant.getCompleteKey(RedisKeyConstant.userAcceptedQuestionIdsSet, user.getId().toString()),
                        id.toString()
                );
            }
            // 管理员不参与Top10
            if (Objects.equals(user.getUserRole(), AuthConstant.USER)) {
                zSetOperations.add(
                        RedisKeyConstant.top10,  //key
                        JSONUtil.toJsonStr(
                                Top10VO.builder()
                                        .userId(user.getId())
                                        .build()
                        )  //value
                        ,
                        user.getScore()  //score
                );
            }
        }
        // 填入题目总数
        stringRedisTemplate.opsForValue().set(RedisKeyConstant.questionNumber, String.valueOf(questionMapper.getQuestionNumber()));
        // 填入总题目提交数和总题目通过数
        Long totalQuestionSubmitNumber = questionSubmitMapper.selectCount(null);
        Long totalQuestionAcceptedNumber = questionSubmitMapper.selectCount(
                new QueryWrapper<QuestionSubmit>()
                        .eq("judgeResult", "Accepted")
        );
        stringRedisTemplate.opsForValue().set(RedisKeyConstant.totalQuestionSubmitNumber, totalQuestionSubmitNumber.toString());
        stringRedisTemplate.opsForValue().set(RedisKeyConstant.totalQuestionAcceptedNumber, totalQuestionAcceptedNumber.toString());
        // adminIds
        userMapper.selectObjs(
                        new QueryWrapper<User>().select("id")
                                .eq("userRole", "admin")
                ).stream()
                .map(Object::toString)
                .forEach(id -> {
                    stringRedisTemplate.opsForSet().add(
                            RedisKeyConstant.adminIds,
                            id
                    );
                });
        log.info("Redis初始化成功");

    }
}